#pragma ance

#include <cstring>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdio>

#ifdef __linux__
    #include <sys/types.h>       
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include "log.hpp"
    extern Log lg;
#elif _WIN32
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <windows.h>

    #pragma comment(lib, "ws2_32.lib")
#endif

enum ErrorHandle
{
    Sock_Error = 1,
    Bind_Error,
    Listen_Error
};

ErrorHandle sock_error = Sock_Error;
ErrorHandle bind_error = Bind_Error;
ErrorHandle listen_error = Listen_Error;

#ifdef __linux__
const int backlog = 8;

class Sock
{
public:
    //创建套接字
    void Socket()
    {
        _listenSock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenSock < 0)
        {
            lg(Fatal, "sock error, code:%d, message:%s", errno, strerror(errno));
            exit(sock_error);
        }
        lg(Info, "sock success");
        int opt = 1;
        setsockopt(_listenSock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
    }

    //绑定
    void Bind(uint16_t port)
    {
        struct sockaddr_in local;
        bzero(&local, sizeof(struct sockaddr_in));
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;

        socklen_t len = sizeof(local);
        if (bind(_listenSock, (const sockaddr*)&local, len) < 0)
        {
            lg(Fatal, "bind error, code:%d, message%s", errno, strerror(errno));
            exit(bind_error);
        }
        lg(Info, "bind success");
    }

    void Listen()
    {
        if (listen(_listenSock, backlog) < 0)
        {
            lg(Fatal, "listen error, code%d, message%s", errno, strerror(errno));
            exit(listen_error);
        }
        lg(Info, "listen success");
    }

    int Accept(std::string& ip, uint16_t& port)
    {
        sockaddr_in client;
        socklen_t len = sizeof(client);
        memset(&client, 0, len);
        int sockid = accept(_listenSock, (struct sockaddr*)&client, &len);
        if (sockid < 0)
            lg(Warning, "accept error");
        else {
            port = ntohs(client.sin_port);
            char buffer[32];
            inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
            ip = buffer;
            lg(Info, "link success... ip:%s, port:%d", ip.c_str(), port);
        }
        return sockid;
    }

    void Close()
    {
        close(_listenSock);
    }

    int GetListenSock()
    {
        return _listenSock;
    }

private:
    int _listenSock;
};
#endif


class ClientSock
{
public:
    void Socket()
    {
    #ifdef _WIN32
        WSADATA wsaData;
        SOCKET client_fd;
        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
            std::cerr << "WSAStartup failed" << std::endl;
            return;
        }
    #endif

        _Sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_Sock < 0)
        {

            printf("sock error, code:%d, message:%s\n", errno, strerror(errno));
            exit(sock_error);
        }
        printf("sock success\n");
    }

    bool Connect(std::string& ip, uint16_t port)
    {
        struct sockaddr_in server;
        socklen_t len = sizeof(struct sockaddr_in);
        server.sin_family = AF_INET;
        server.sin_port = htons(port);
        inet_pton(AF_INET, ip.c_str(), &server.sin_addr);

        int ret = -1, cnt = 0;
        do
        {
            ret = connect(_Sock, (const sockaddr*)&server, len);
            printf("第 %d 次连接...\n", cnt + 1);
            #ifdef __linux__
                sleep(2);
            #else
                Sleep(2000);
            #endif
        }while(ret < 0 && ++cnt < 5);

        if (ret < 0)
            printf("connect error, code:%d, msg:%s\n", errno, strerror(errno));
        else
            printf("client link success\n");

        return ret == 0 ? true : false;
    }

    int GetSock()
    {
        return _Sock;
    }

    void Close()
    {
#ifdef __linux__
        close(_Sock);
#elif _WIN32
        closesocket(_Sock);
#endif
    }
private:
    int _Sock;
};



// int Write(int fd, const void* buf, size_t count)
// {
// #ifdef __linux__
//     return write(fd, buf, count);
// #elif _WIN32
//     return send(fd, (const char*)buf, count, 0);
// #endif
// }

// int Read(int fd, void* buf, size_t count)
// {
// #ifdef __linux__
//     return read(fd, buf, count);
// #elif _WIN32
//     return recv(fd, (char*)buf, count, 0);
// #endif
// }
